Skip to content

feat: add some pagination options #980

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

gfyrag
Copy link
Contributor

@gfyrag gfyrag commented Jun 20, 2025

Fixes LX-62

@gfyrag gfyrag requested a review from a team as a code owner June 20, 2025 09:14
Copy link

coderabbitai bot commented Jun 20, 2025

Walkthrough

This change introduces a new sort query parameter to multiple list endpoints in the Ledger API v2, allowing clients to specify sorting by field and order. It also adds support for paginating and sorting on additional fields, such as first_usage for accounts and date/id for logs and transactions. The account schema is updated to expose a new firstUsage timestamp field. Error handling for pagination is unified, and corresponding documentation and tests are updated.

Changes

Files/Areas Change Summary
docs/api/README.md, pkg/client/docs/models/operations/*.md, pkg/client/docs/sdks/v2/README.md API documentation updated to add the sort parameter for list endpoints, deprecate order, and describe new paginatable fields.
pkg/client/models/operations/*.go, pkg/client/models/components/v2account.go Client models updated to add Sort field to relevant request structs, add FirstUsage to account struct, and mark Order as deprecated.
internal/api/v2/common.go Logic added to parse and validate the new sort parameter, converting field names and handling order.
internal/storage/common/schema.go, internal/storage/ledger/resource_*.go, internal/storage/system/resource_ledgers.go Schemas updated to mark fields as paginated, enabling sorting/pagination on fields like first_usage, address, date, id, etc.
internal/storage/common/errors.go, internal/api/common/errors.go New error types and consolidated error handler for pagination-related errors.
internal/controller/ledger/store.go, internal/storage/ledger/accounts.go, internal/controller/ledger/controller_default.go UpdateAccountsMetadata method signature changed to accept a timestamp, and logic added to preserve earliest first_usage.
internal/account.go, internal/README.md Account struct updated to expose FirstUsage in JSON.
internal/api/v2/controllers_* Controllers updated to use unified pagination error handler.
Test files (test/e2e/api_*.go, internal/api/v2/views_test.go, etc.) Tests updated to cover new sorting options, paginatable fields, firstUsage field, and to use new helper functions for assertions.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant API
    participant Storage

    Client->>API: GET /v2/{ledger}/accounts?sort=first_usage:asc
    API->>API: Parse 'sort' parameter (field + order)
    API->>Storage: Query accounts, paginate/sort by first_usage ASC
    Storage-->>API: Accounts list (sorted, paginated)
    API-->>Client: Response with accounts (includes firstUsage)
Loading
sequenceDiagram
    participant Client
    participant API
    participant Storage

    Client->>API: GET /v2/{ledger}/logs?sort=date:desc
    API->>API: Parse 'sort' parameter (field + order)
    API->>Storage: Query logs, paginate/sort by date DESC
    Storage-->>API: Logs list (sorted, paginated)
    API-->>Client: Response with logs
Loading

Assessment against linked issues

Objective Addressed Explanation
Add sort query param to list endpoints (LX-62)
Support paginating/sorting accounts by first_usage (asc/desc) and address (desc) (LX-62)
Support paginating/sorting volumes by address (desc) (LX-62)
Support paginating/sorting logs by date (asc/desc) and id (asc) (LX-62)

Assessment against linked issues: Out-of-scope changes

No out-of-scope changes found.

Possibly related PRs

  • formancehq/ledger#978: Refactors pagination system and interfaces, which directly relates to the introduction of the new sort parameter and schema changes in this PR.
  • formancehq/ledger#615: Refactors store and controller interfaces for pagination, which aligns with the changes to query handling and schema in this PR.
  • formancehq/ledger#911: Adds a reverse parameter for transaction list ordering, which is related to the new generalized sorting logic introduced here.

Suggested labels

build-images

Suggested reviewers

  • laouji
  • paul-nicolas

Poem

A hop, a skip, a sort so neat,
Now ledgers line up, accounts compete.
First usage shines, logs align,
Pagination flows, all by design.
With every field now sortable too,
This bunny says: "Well done to you!"
🐇✨

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate Unit Tests
  • Create PR with Unit Tests
  • Post Copyable Unit Tests in Comment
  • Commit Unit Tests in branch feat/add-pagination-options

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai auto-generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

cursor[bot]

This comment was marked as outdated.

@gfyrag gfyrag force-pushed the feat/add-pagination-options branch from 0545e6a to ffcd47d Compare June 20, 2025 10:11
Copy link

codecov bot commented Jun 20, 2025

Codecov Report

Attention: Patch coverage is 69.81132% with 16 lines in your changes missing coverage. Please review.

Project coverage is 82.91%. Comparing base (b708297) to head (6fd34bf).

Files with missing lines Patch % Lines
internal/storage/common/errors.go 0.00% 9 Missing ⚠️
internal/storage/common/resource.go 0.00% 2 Missing and 1 partial ⚠️
internal/api/v2/common.go 81.81% 2 Missing ⚠️
internal/api/v2/controllers_volumes.go 0.00% 1 Missing ⚠️
internal/controller/ledger/controller_default.go 0.00% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #980      +/-   ##
==========================================
- Coverage   82.98%   82.91%   -0.07%     
==========================================
  Files         145      145              
  Lines        8199     8219      +20     
==========================================
+ Hits         6804     6815      +11     
- Misses       1071     1079       +8     
- Partials      324      325       +1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug

The UpdateAccountsMetadata method now accepts a time.Time parameter (at) to set FirstUsage. This introduces two issues with the SQL update logic for first_usage:

  1. When time.Time{} (zero time, January 1, year 1) is passed for at (e.g., in test calls or metadata-only updates), the case when excluded.first_usage < accounts.first_usage then excluded.first_usage else accounts.first_usage end condition incorrectly sets first_usage to zero time, as zero time is always earlier than any valid timestamp. This can overwrite existing correct first_usage values.
  2. The same SQL logic fails to correctly set first_usage when accounts.first_usage is NULL and excluded.first_usage has a real timestamp. The comparison real_date < NULL evaluates to NULL (unknown), causing the CASE statement to retain the NULL value.
    These issues lead to first_usage being corrupted or not set properly, preventing accurate tracking of account first usage.

internal/storage/ledger/accounts.go#L24-L62

func (store *Store) UpdateAccountsMetadata(ctx context.Context, m map[string]metadata.Metadata, at time.Time) error {
_, err := tracing.TraceWithMetric(
ctx,
"UpdateAccountsMetadata",
store.tracer,
store.updateAccountsMetadataHistogram,
tracing.NoResult(func(ctx context.Context) error {
span := trace.SpanFromContext(ctx)
span.SetAttributes(attribute.StringSlice("accounts", Keys(m)))
type AccountWithLedger struct {
ledger.Account `bun:",extend"`
Ledger string `bun:"ledger,type:varchar"`
AddressArray []string `bun:"address_array,type:jsonb"`
}
accounts := make([]AccountWithLedger, 0)
for account, accountMetadata := range m {
accounts = append(accounts, AccountWithLedger{
Ledger: store.ledger.Name,
Account: ledger.Account{
Address: account,
Metadata: accountMetadata,
FirstUsage: at,
},
AddressArray: strings.Split(account, ":"),
})
}
ret, err := store.db.NewInsert().
Model(&accounts).
ModelTableExpr(store.GetPrefixedRelationName("accounts")).
On("conflict (ledger, address) do update").
Set("metadata = accounts.metadata || excluded.metadata").
Set("updated_at = excluded.updated_at").
Set("first_usage = case when excluded.first_usage < accounts.first_usage then excluded.first_usage else accounts.first_usage end").
Where("not accounts.metadata @> excluded.metadata").

Fix in Cursor


Was this report helpful? Give feedback by reacting with 👍 or 👎

Base automatically changed from refacto/pagination-system to main June 24, 2025 10:07
@gfyrag gfyrag force-pushed the feat/add-pagination-options branch from ffcd47d to 6fd34bf Compare June 24, 2025 10:14
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🔭 Outside diff range comments (3)
docs/api/README.md (3)

139-153: Document the exact list of sortable fields and default order

The new sort parameter is introduced but the doc omits:
• the exhaustive list of fields that are accepted for this endpoint,
• what happens when the caller omits <order> (is asc assumed?),
• case-sensitivity expectations (asc|ASC?),
• behaviour when an unknown field is supplied.

Without this information the contract is underspecified and client implementations will diverge.


1164-1180: Deprecation notice needs stronger signalling and cross-param rules

  1. Mark the order parameter with a clear “DEPRECATED” badge (or x-deprecated in the OpenAPI spec) so generators surface it.
  2. State whether order, reverse, and sort are mutually exclusive and which one wins if both are provided.

1879-1893: Volumes endpoint: clarify sortable fields

Volumes expose composite objects (account, asset, input, …). List which of these are sortable and whether secondary ordering is guaranteed for ties.

♻️ Duplicate comments (1)
docs/api/README.md (1)

744-758: Repeat the same clarification for the accounts endpoint

Same gaps as noted above: accepted fields, default order, error semantics. Make sure the wording is consistent across all endpoints to avoid copy-paste drift.

🧹 Nitpick comments (6)
pkg/client/docs/models/operations/v2listtransactionsrequest.md (1)

13-13: Fix markdown formatting issues.

The static analysis tool correctly identifies spacing issues within the emphasis markers (strikethrough formatting).

Apply this diff to fix the formatting:

-| ~~`Order`~~                                                                                                                                              | [*operations.Order](../../models/operations/order.md)                                                                                                    | :heavy_minus_sign:                                                                                                                                       | : warning: ** DEPRECATED **: This will be removed in a future release, please migrate away from it as soon as possible.<br/><br/>Deprecated: Use sort param                                              |                                                                                                                                                          |
+| ~~`Order`~~                                                                                                                                              | [*operations.Order](../../models/operations/order.md)                                                                                                    | :heavy_minus_sign:                                                                                                                                       | :warning: **DEPRECATED**: This will be removed in a future release, please migrate away from it as soon as possible.<br/><br/>Deprecated: Use sort param                                              |                                                                                                                                                          |
test/e2e/api_accounts_list_test.go (2)

166-176: Enhance test to verify sorting behavior.

The test verifies that the API call with sort=first_usage:asc succeeds, but doesn't validate that the results are actually sorted correctly. Consider adding assertions to verify the accounts are returned in the expected order.

 It("should be listed on api while paginating on first usage", func(specContext SpecContext) {
-	_, err := Wait(specContext, DeferClient(testServer)).Ledger.V2.ListAccounts(
+	response, err := Wait(specContext, DeferClient(testServer)).Ledger.V2.ListAccounts(
 		ctx,
 		operations.V2ListAccountsRequest{
 			Ledger: "default",
 			Expand: pointer.For("volumes"),
 			Sort:   pointer.For("first_usage:asc"),
 		},
 	)
 	Expect(err).ToNot(HaveOccurred())
+
+	// Verify accounts are sorted by first_usage in ascending order
+	accounts := response.V2AccountsCursorResponse.Cursor.Data
+	for i := 1; i < len(accounts); i++ {
+		if accounts[i-1].FirstUsage != nil && accounts[i].FirstUsage != nil {
+			Expect(accounts[i-1].FirstUsage.Before(*accounts[i].FirstUsage) || 
+				   accounts[i-1].FirstUsage.Equal(*accounts[i].FirstUsage)).To(BeTrue())
+		}
+	}
 })

323-347: Refactor to eliminate code duplication.

The listAccounts helper function normalizes FirstUsage fields, but similar normalization code exists in the BeforeEach block, creating duplication.

 listAccounts := func(specContext SpecContext, request operations.V2ListAccountsRequest) *operations.V2ListAccountsResponse {
 	GinkgoHelper()
 	response, err = Wait(specContext, DeferClient(testServer)).Ledger.V2.ListAccounts(ctx, request)
 	Expect(err).ToNot(HaveOccurred())

 	// We don't have firstUsage value, so we set it to nil to be able to compare accounts list
 	for ind, account := range response.V2AccountsCursorResponse.Cursor.Data {
 		account.FirstUsage = nil
 		response.V2AccountsCursorResponse.Cursor.Data[ind] = account
 	}

 	return response
 }
 BeforeEach(func(specContext SpecContext) {
 	response = listAccounts(specContext, operations.V2ListAccountsRequest{
 		Ledger:   "default",
 		PageSize: pointer.For(pageSize),
 	})

-	// We don't have firstUsage value, so we set it to nil to be able to compare accounts list
-	for ind, account := range response.V2AccountsCursorResponse.Cursor.Data {
-		account.FirstUsage = nil
-		response.V2AccountsCursorResponse.Cursor.Data[ind] = account
-	}

 	Expect(response.V2AccountsCursorResponse.Cursor.HasMore).To(BeTrue())
 	Expect(response.V2AccountsCursorResponse.Cursor.Previous).To(BeNil())
 	Expect(response.V2AccountsCursorResponse.Cursor.Next).NotTo(BeNil())
 })
docs/api/README.md (3)

776-777: Align example timestamps

firstUsage here uses 2023-01-01T00:00:00Z whereas the rest of the examples still use the 2019-08-24T14:15:22Z convention. Pick one convention so users don’t wonder if the value carries a special meaning.


861-862: Add a description to firstUsage

The schema table later shows "none" in the description column. A short explanation such as “ISO-8601 timestamp of the first recorded transaction involving this account” will improve discoverability.


2550-2556: Schema table missing firstUsage description

Same as earlier comment: add a concise description. Also double-check that the property is flagged as readOnly in the OpenAPI spec if clients are not supposed to supply it.

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b708297 and 6fd34bf.

⛔ Files ignored due to path filters (8)
  • go.mod is excluded by !**/*.mod
  • go.sum is excluded by !**/*.sum, !**/*.sum
  • openapi.yaml is excluded by !**/*.yaml
  • openapi/v2.yaml is excluded by !**/*.yaml
  • pkg/client/.speakeasy/gen.lock is excluded by !**/*.lock, !**/*.lock
  • pkg/client/.speakeasy/logs/naming.log is excluded by !**/*.log, !**/*.log
  • pkg/client/speakeasyusagegen/.speakeasy/logs/naming.log is excluded by !**/*.log, !**/*.log
  • tools/generator/go.sum is excluded by !**/*.sum, !**/*.sum
📒 Files selected for processing (47)
  • docs/api/README.md (16 hunks)
  • internal/README.md (1 hunks)
  • internal/account.go (1 hunks)
  • internal/api/common/errors.go (2 hunks)
  • internal/api/v2/common.go (2 hunks)
  • internal/api/v2/controllers_accounts_list.go (1 hunks)
  • internal/api/v2/controllers_ledgers_list.go (1 hunks)
  • internal/api/v2/controllers_logs_list.go (1 hunks)
  • internal/api/v2/controllers_transactions_list.go (1 hunks)
  • internal/api/v2/controllers_volumes.go (1 hunks)
  • internal/api/v2/views_test.go (2 hunks)
  • internal/controller/ledger/controller_default.go (1 hunks)
  • internal/controller/ledger/store.go (1 hunks)
  • internal/controller/ledger/store_generated_test.go (1 hunks)
  • internal/storage/common/errors.go (1 hunks)
  • internal/storage/common/resource.go (1 hunks)
  • internal/storage/common/schema.go (1 hunks)
  • internal/storage/ledger/accounts.go (4 hunks)
  • internal/storage/ledger/accounts_test.go (3 hunks)
  • internal/storage/ledger/balances_test.go (2 hunks)
  • internal/storage/ledger/resource_accounts.go (1 hunks)
  • internal/storage/ledger/resource_aggregated_balances.go (1 hunks)
  • internal/storage/ledger/resource_logs.go (1 hunks)
  • internal/storage/ledger/resource_transactions.go (1 hunks)
  • internal/storage/ledger/resource_volumes.go (1 hunks)
  • internal/storage/ledger/volumes_test.go (2 hunks)
  • internal/storage/system/resource_ledgers.go (1 hunks)
  • pkg/client/docs/models/components/v2account.md (1 hunks)
  • pkg/client/docs/models/operations/order.md (1 hunks)
  • pkg/client/docs/models/operations/v2getvolumeswithbalancesrequest.md (1 hunks)
  • pkg/client/docs/models/operations/v2listaccountsrequest.md (1 hunks)
  • pkg/client/docs/models/operations/v2listledgersrequest.md (1 hunks)
  • pkg/client/docs/models/operations/v2listlogsrequest.md (1 hunks)
  • pkg/client/docs/models/operations/v2listtransactionsrequest.md (1 hunks)
  • pkg/client/docs/sdks/v2/README.md (5 hunks)
  • pkg/client/models/components/v2account.go (2 hunks)
  • pkg/client/models/operations/v2getvolumeswithbalances.go (2 hunks)
  • pkg/client/models/operations/v2listaccounts.go (2 hunks)
  • pkg/client/models/operations/v2listledgers.go (2 hunks)
  • pkg/client/models/operations/v2listlogs.go (2 hunks)
  • pkg/client/models/operations/v2listtransactions.go (3 hunks)
  • test/e2e/api_accounts_list_test.go (9 hunks)
  • test/e2e/api_accounts_metadata_test.go (4 hunks)
  • test/e2e/api_logs_list_test.go (1 hunks)
  • test/e2e/api_transactions_create_test.go (3 hunks)
  • test/e2e/api_transactions_list_test.go (2 hunks)
  • test/e2e/api_volumes_test.go (7 hunks)
🧰 Additional context used
🪛 markdownlint-cli2 (0.17.2)
pkg/client/docs/models/operations/v2listtransactionsrequest.md

13-13: Spaces inside emphasis markers
null

(MD037, no-space-in-emphasis)


13-13: Spaces inside emphasis markers
null

(MD037, no-space-in-emphasis)

⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: Tests
  • GitHub Check: Dirty
🔇 Additional comments (59)
internal/api/v2/views_test.go (1)

384-384: Test updates correctly reflect the new firstUsage field exposure.

The addition of "firstUsage" to the expected JSON output properly aligns with the change in internal/account.go where the FirstUsage field's JSON tag was updated from "-" to "firstUsage". This ensures test coverage accurately validates the API response structure.

Also applies to: 411-411

pkg/client/docs/models/operations/order.md (1)

3-4: Clear deprecation notice provides proper migration guidance.

The deprecation notice is well-formatted and clearly directs users to the new sort parameter, supporting the transition from the legacy order parameter. This follows good API versioning practices.

internal/account.go (1)

19-19: Field exposure change implemented correctly.

Changing the JSON tag from "-" to "firstUsage" properly exposes the FirstUsage timestamp in API responses. The database mapping remains unchanged, ensuring data consistency. This is a breaking API change that should be documented in release notes.

pkg/client/docs/models/components/v2account.md (1)

10-10: Documentation accurately reflects the new field addition.

The FirstUsage field documentation is properly formatted with correct type information, optional designation, and a valid RFC3339 timestamp example. This aligns with the implementation changes in the Account model.

internal/controller/ledger/controller_default.go (1)

277-277: Verify method signature consistency across the codebase.

The addition of log.Date as a third argument to UpdateAccountsMetadata appears to align with an updated method signature. Ensure this change is consistently applied everywhere this method is called.

#!/bin/bash
# Search for all calls to UpdateAccountsMetadata to verify signature consistency
rg -A 3 -B 1 "UpdateAccountsMetadata"
pkg/client/docs/models/operations/v2listlogsrequest.md (1)

12-12: Documentation correctly added for new Sort parameter.

The new Sort field is properly documented with clear format specification and a valid example. The field type, requirement status, and description are consistent with the existing documentation style.

pkg/client/docs/models/operations/v2listledgersrequest.md (1)

10-10: Consistent documentation for Sort parameter.

The Sort field documentation matches the pattern established in other request models, ensuring API consistency across endpoints.

internal/api/v2/controllers_transactions_list.go (1)

33-33: Good refactoring to consolidate error handling.

Replacing specific error type checks with common.HandleCommonPaginationErrors reduces code duplication and ensures consistent error handling across controllers. This aligns well with the DRY principle.

internal/storage/ledger/volumes_test.go (2)

49-49: Method signature updated correctly.

The addition of time.Time{} parameter aligns with the updated UpdateAccountsMetadata method signature. Using zero time appears appropriate for test scenarios where the timestamp context is not critical.


545-545: Consistent signature update.

This change matches the previous update at line 49, maintaining consistency in the test file.

pkg/client/docs/models/operations/v2listaccountsrequest.md (1)

13-13: Complete and consistent Sort parameter documentation.

The Sort field documentation maintains consistency across all list request models, providing a unified API experience for pagination and sorting functionality.

pkg/client/docs/sdks/v2/README.md (1)

65-65: Documentation updates look good and consistent.

The SDK documentation has been properly updated to demonstrate the new Sort parameter across all relevant operations. The consistent use of "id:desc" as the example value provides clear guidance for developers on the expected format.

Also applies to: 568-568, 940-940, 1419-1419, 1484-1484

internal/storage/ledger/resource_logs.go (1)

17-18: Schema changes correctly enable pagination support.

Marking the "date" and "id" fields as paginated is the appropriate way to enable sorting and pagination functionality for these fields. This aligns well with the broader API enhancements for pagination support.

internal/storage/ledger/resource_volumes.go (1)

20-26: Schema changes correctly enable pagination support for the address field.

The addition of .Paginated() to the "address" field properly enables pagination and sorting functionality. The code formatting improvements also enhance readability.

test/e2e/api_volumes_test.go (1)

86-86: LGTM: Improved test description consistency.

The changes to test descriptions improve consistency by using lowercase style throughout the test suite. The test logic and coverage remain unchanged.

Also applies to: 115-115, 143-143, 170-170, 198-198, 216-216, 231-231

internal/storage/common/resource.go (1)

287-289: Excellent validation enhancement for pagination security.

This validation properly prevents pagination on fields that aren't marked as paginated, improving both security and correctness. The error handling follows established patterns and provides clear feedback to consumers.

pkg/client/docs/models/operations/v2getvolumeswithbalancesrequest.md (1)

15-15: Clear and well-documented Sort parameter.

The documentation clearly specifies the Sort parameter format and provides a helpful example. The <field>:<order> format is intuitive and follows common API conventions.

internal/storage/common/schema.go (1)

28-28: Clean implementation of pagination field marking.

The addition of the IsPaginated field and Paginated() method follows established patterns in the codebase. The fluent interface design is consistent with existing methods like WithAliases().

Also applies to: 36-39

internal/api/v2/controllers_logs_list.go (1)

23-23: Good refactoring to centralize pagination error handling.

Delegating pagination error handling to common.HandleCommonPaginationErrors improves consistency across controllers and reduces code duplication. This maintains the same error handling behavior while being more maintainable.

internal/storage/ledger/accounts_test.go (1)

52-52: LGTM: Method signature updates are consistent.

The calls to UpdateAccountsMetadata have been consistently updated to include the new time.Time{} parameter, aligning with the method signature change that supports FirstUsage timestamp handling.

Also applies to: 302-302, 333-333

internal/storage/ledger/balances_test.go (1)

199-199: LGTM: Consistent method signature updates.

The UpdateAccountsMetadata calls have been properly updated to include the new time.Time{} parameter, maintaining consistency with the signature changes applied across the test suite.

Also applies to: 213-213

internal/api/v2/controllers_ledgers_list.go (1)

23-23: LGTM: Improved error handling consolidation.

The delegation to common.HandleCommonPaginationErrors unifies error handling across API endpoints and aligns with the pagination enhancement goals of this PR.

internal/storage/ledger/resource_aggregated_balances.go (1)

18-18: LGTM: Address field marked for pagination support.

Adding .Paginated() to the address field enables sorting and pagination capabilities for this commonly queried field, supporting the PR's pagination enhancement objectives.

internal/README.md (1)

235-235: LGTM: FirstUsage field exposed for JSON serialization.

The change from json:"-" to json:"firstUsage" properly exposes the FirstUsage timestamp field for API responses, enabling sorting capabilities on this field as part of the pagination enhancements.

internal/api/v2/controllers_volumes.go (1)

78-78: LGTM: Error handling consolidation improves consistency.

The replacement of specific error checks with common.HandleCommonPaginationErrors aligns with the broader refactoring pattern across controllers and improves code maintainability.

internal/storage/system/resource_ledgers.go (1)

26-26: LGTM: Schema enhancement supports new pagination features.

Marking the "id" field as paginated enables sorting and pagination on this field, which is consistent with the broader enhancement to support the new sort query parameter across endpoints.

pkg/client/models/operations/v2listlogs.go (2)

22-27: LGTM: Well-documented sort parameter addition.

The new Sort field is properly documented with clear format specification (<field>:<order>), making it easy for API consumers to understand the expected input format.


70-75: LGTM: Nil-safe getter method.

The GetSort() method correctly implements nil-safety, returning nil when the receiver is nil, which is consistent with the pattern used in other getter methods.

internal/api/v2/controllers_accounts_list.go (1)

23-23: LGTM: Consistent error handling pattern.

The use of common.HandleCommonPaginationErrors maintains consistency with other controllers and improves error handling maintainability across the codebase.

internal/controller/ledger/store.go (1)

45-45: ```shell
#!/bin/bash
echo "=== Verifying test call signatures in volumes_test.go ==="
rg -n "store.UpdateAccountsMetadata" -C 2 internal/storage/ledger/volumes_test.go

echo "=== Verifying test call signatures in balances_test.go ==="
rg -n "store.UpdateAccountsMetadata" -C 2 internal/storage/ledger/balances_test.go


</details>
<details>
<summary>internal/storage/ledger/resource_accounts.go (1)</summary>

`19-20`: **LGTM: Schema fields correctly marked as paginated.**

The addition of `.Paginated()` to both "address" and "first_usage" fields properly enables sorting and pagination support for these fields, which aligns with the PR's pagination enhancement objectives.

</details>
<details>
<summary>pkg/client/docs/models/operations/v2listtransactionsrequest.md (1)</summary>

`15-15`: **LGTM: Sort field properly documented.**

The new Sort field documentation clearly explains the format (`<field>:<order>`) and provides a helpful example (`id:desc`), making it easy for API consumers to understand how to use the new sorting functionality.

</details>
<details>
<summary>pkg/client/models/operations/v2getvolumeswithbalances.go (2)</summary>

`28-32`: **LGTM: Sort field properly implemented.**

The Sort field is correctly added with appropriate documentation, query parameter tags, and follows the established pattern for optional fields in the request struct.

---

`96-101`: **LGTM: Getter method follows established pattern.**

The GetSort() method correctly implements nil safety checks consistent with other getter methods in the struct, ensuring safe access to the Sort field.

</details>
<details>
<summary>test/e2e/api_transactions_create_test.go (1)</summary>

`127-127`: **LGTM: Test assertions properly validate FirstUsage field.**

The test updates correctly verify that the FirstUsage field is present and properly populated in account responses, ensuring the new timestamp functionality works as expected across different transaction scenarios.



Also applies to: 140-140, 282-282

</details>
<details>
<summary>internal/api/common/errors.go (2)</summary>

`5-5`: **LGTM: Appropriate import added for error handling.**

The storagecommon import is correctly added to support the new pagination error types used in the HandleCommonPaginationErrors function.

---

`56-65`: **LGTM: Well-designed error handling consolidation.**

The HandleCommonPaginationErrors function effectively centralizes pagination-related error handling by covering the key error types:
- `ErrInvalidQuery` for malformed pagination queries
- `ErrMissingFeature` for feature availability issues  
- `ErrNotPaginatedField` for attempts to paginate on unsupported fields

This consolidation improves code maintainability and ensures consistent error responses across different API controllers.

</details>
<details>
<summary>pkg/client/models/operations/v2listledgers.go (1)</summary>

`18-45`: **LGTM! Well-implemented sorting parameter.**

The `Sort` field addition follows the established patterns in the struct with proper query parameter annotations, clear documentation, and consistent getter method implementation. The format specification `<field>:<order>` is clear and the nil-safety in the getter matches other methods.

</details>
<details>
<summary>internal/storage/ledger/resource_transactions.go (1)</summary>

`22-24`: **LGTM! Appropriate fields marked for pagination.**

Marking `timestamp` and `id` fields as paginated is logical for transaction sorting. These are the most commonly used fields for ordering transaction lists and align well with the new sorting functionality.

</details>
<details>
<summary>pkg/client/models/operations/v2listaccounts.go (1)</summary>

`22-83`: **LGTM! Consistent sorting implementation across endpoints.**

The `Sort` field implementation for accounts follows the same pattern as other list operations, maintaining consistency across the API. The documentation and getter method are properly implemented.

</details>
<details>
<summary>test/e2e/api_accounts_metadata_test.go (1)</summary>

`77-78`: **LGTM! Appropriate test adaptation for schema changes.**

The change from full struct equality checks to individual field assertions is a good approach to handle the addition of the `FirstUsage` field to the account schema. The tests continue to validate the core metadata functionality while being more resilient to schema additions.




Also applies to: 107-108, 128-129, 155-156

</details>
<details>
<summary>test/e2e/api_transactions_list_test.go (2)</summary>

`130-158`: **LGTM! Comprehensive test coverage for sorting functionality.**

The new test case thoroughly validates the `Sort` parameter with `timestamp:desc` ordering. The test setup properly sorts expected data locally and compares it with the API response, ensuring the sorting logic works correctly end-to-end.

---

`240-240`: **LGTM! Appropriate handling of deprecated field.**

The `//nolint:staticcheck` directive is correctly used to suppress warnings for the deprecated `Order` field while maintaining test coverage for backward compatibility.

</details>
<details>
<summary>internal/api/v2/common.go (2)</summary>

`4-4`: **LGTM! Proper imports added for new functionality.**

The `fmt` and `strcase` imports are correctly added to support error formatting and column name case conversion for the new sort parameter functionality.



Also applies to: 8-8

---

`94-107`: **Well-implemented sort parameter parsing with proper validation.**

The sort parameter parsing logic is correctly implemented:
- Uses `SplitN` with limit 2 to handle column names that might contain colons
- Converts column names to snake_case for consistency
- Validates order values (asc/desc) with case-insensitive comparison
- Returns descriptive errors for invalid input

The implementation follows good API design practices and handles edge cases properly.

</details>
<details>
<summary>internal/storage/ledger/accounts.go (3)</summary>

`8-8`: **LGTM! Proper import added for time functionality.**

The time import is correctly added to support the new `at time.Time` parameter in the method signature.

---

`25-25`: **Correctly implemented first usage timestamp tracking.**

The method signature update and FirstUsage field assignment properly implement the new feature:
- The `at time.Time` parameter allows callers to specify the timestamp
- Setting `FirstUsage: at` ensures the timestamp is captured for new accounts

This change aligns with the broader API enhancement for tracking account first usage.



Also applies to: 49-49

---

`61-61`: **Excellent SQL logic for preserving earliest first usage timestamp.**

The upsert logic correctly uses a CASE statement to preserve the earliest `first_usage` value:
```sql
first_usage = case when excluded.first_usage < accounts.first_usage then excluded.first_usage else accounts.first_usage end

This ensures that the first usage timestamp is never overwritten with a later timestamp, maintaining data integrity for historical tracking.

internal/storage/common/errors.go (1)

24-41: Well-designed error type following Go best practices.

The ErrNotPaginatedField error type is properly implemented:

  • Contains contextual information (field name) for debugging
  • Implements standard Error() method with clear, descriptive message
  • Includes Is() method for proper error comparison and handling
  • Uses unexported constructor function to maintain API consistency

This error type will effectively support the new pagination validation features.

internal/controller/ledger/store_generated_test.go (1)

314-316: LGTM! Mock implementation correctly updated to match interface changes.

The generated mock method signature has been properly updated to include the new at time.Time parameter, maintaining consistency with the Store interface changes. The mock recorder methods are also correctly updated to handle the additional parameter.

Also applies to: 322-324

pkg/client/models/components/v2account.go (4)

5-9: LGTM! Proper imports added for extended functionality.

The import updates correctly add the necessary packages:

  • utils for JSON marshaling/unmarshaling consistency
  • time package for the new FirstUsage field

13-13: Correctly implemented optional FirstUsage field.

The FirstUsage field is properly defined as an optional pointer type (*time.Time) with the correct JSON tag "firstUsage,omitempty". This allows the field to be omitted when null and follows the API specification.


18-27: Proper JSON serialization methods for consistency.

The custom MarshalJSON and UnmarshalJSON methods correctly delegate to internal utility functions, ensuring consistent JSON handling across the client SDK. This maintains the established patterns in the codebase.


43-48: Well-implemented getter method with nil-safety.

The GetFirstUsage() method follows the established pattern with proper nil-checking, ensuring safe access to the optional FirstUsage field. This maintains consistency with other getter methods in the struct.

pkg/client/models/operations/v2listtransactions.go (3)

13-13: LGTM: Proper deprecation handling.

The deprecation of the Order type and field is handled correctly with clear messaging directing users to the new sort parameter while maintaining backwards compatibility.

Also applies to: 51-54


56-59: LGTM: Well-documented Sort field.

The new Sort field is properly implemented with clear documentation explaining the expected format and consistent struct tags.


123-128: LGTM: Consistent getter method implementation.

The GetSort() method follows the established pattern used by other getter methods in the struct, with proper nil checking and correct return type.

test/e2e/api_accounts_list_test.go (1)

139-141: LGTM: Proper FirstUsage field integration.

The FirstUsage field has been correctly added to the test assertions and expected account structures, using the appropriate timestamp values.

Also applies to: 151-151, 156-156

docs/api/README.md (1)

1962-1976: Logs endpoint: mismatch between example and docs

The text says “sorted by ID in descending order” but the new sort param allows overriding this. Explicitly document the current default (id:desc) and note that supplying sort overrides it.

Comment on lines +126 to +137
When("paginating on date", func() {
It("should be ok", func(specContext SpecContext) {
_, err := Wait(specContext, DeferClient(testServer)).Ledger.V2.ListLogs(
ctx,
operations.V2ListLogsRequest{
Ledger: "default",
Sort: pointer.For("date:asc"),
},
)
Expect(err).ToNot(HaveOccurred())
})
})
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Consider enhancing test coverage for sorting functionality.

The current test only verifies that the API accepts the sort parameter without error, but doesn't validate the actual sorting behavior. For comprehensive testing of this new feature, consider adding assertions to verify:

  • The response data is actually sorted by date in ascending order
  • Different sort parameters work correctly (e.g., "id:desc", "date:desc")
  • Error handling for invalid sort parameters

Example enhancement:

When("paginating on date", func() {
	It("should be ok", func(specContext SpecContext) {
-		_, err := Wait(specContext, DeferClient(testServer)).Ledger.V2.ListLogs(
+		response, err := Wait(specContext, DeferClient(testServer)).Ledger.V2.ListLogs(
			ctx,
			operations.V2ListLogsRequest{
				Ledger: "default",
				Sort:   pointer.For("date:asc"),
			},
		)
		Expect(err).ToNot(HaveOccurred())
+		
+		// Verify logs are sorted by date in ascending order
+		logs := response.V2LogsCursorResponse.Cursor.Data
+		for i := 1; i < len(logs); i++ {
+			Expect(logs[i].Date.After(logs[i-1].Date) || logs[i].Date.Equal(logs[i-1].Date)).To(BeTrue())
+		}
	})
})
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
When("paginating on date", func() {
It("should be ok", func(specContext SpecContext) {
_, err := Wait(specContext, DeferClient(testServer)).Ledger.V2.ListLogs(
ctx,
operations.V2ListLogsRequest{
Ledger: "default",
Sort: pointer.For("date:asc"),
},
)
Expect(err).ToNot(HaveOccurred())
})
})
When("paginating on date", func() {
It("should be ok", func(specContext SpecContext) {
response, err := Wait(specContext, DeferClient(testServer)).Ledger.V2.ListLogs(
ctx,
operations.V2ListLogsRequest{
Ledger: "default",
Sort: pointer.For("date:asc"),
},
)
Expect(err).ToNot(HaveOccurred())
// Verify logs are sorted by date in ascending order
logs := response.V2LogsCursorResponse.Cursor.Data
for i := 1; i < len(logs); i++ {
Expect(logs[i].Date.After(logs[i-1].Date) || logs[i].Date.Equal(logs[i-1].Date)).To(BeTrue())
}
})
})
🤖 Prompt for AI Agents
In test/e2e/api_logs_list_test.go around lines 126 to 137, the test only checks
that the API accepts the sort parameter without error but does not verify the
sorting behavior. Enhance the test by adding assertions to confirm the response
data is sorted by date ascending, add additional test cases for other sort
parameters like "id:desc" and "date:desc", and include tests for error handling
when invalid sort parameters are provided.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants